home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
wil4c10.zip
/
NEWS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-26
|
17KB
|
588 lines
/*
** --- news.c ---
**
** This program can:
**
** (1) List all newsgroups.
** (2) Select a news group.
** (3) Get article head from selected newsgroup.
** (4) Get article body from selected newsgroup.
**
** Articles (specified by article number) are saved
** to disk with extension ".ART".
**
** The group list (LIST command) is saved to NEWS.LST
**
** You must be authenicated with the news service you connect to.
*/
#include <windows.h>
#include <winsock.h>
#include "wil.h"
#include "message.h"
#include "about.h"
#include "paint.h"
#include "str.h"
#include "async.h"
#ifdef WIN32
#define USE_INS HINSTANCE
#define USE_PTR PSTR
#else
#define USE_INS HANDLE
#define USE_PTR LPSTR
#endif
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
/* globals */
HWND hMainWnd; /* main window handle */
#define BS 8
#define LF 10
#define CR 13
#define ESC 27
#define MAX_BUF 128
#define STR_SIZE 40
#define NNTP_PORT 119
#define ONE_SEC 1000
#define QUOTE 0x22
/* messages generated by calling PostMessage() [see POST_MSG below] */
#define USER_CONNECT 101
#define USER_CONN_SUCCESS 102
#define USER_CONN_FAILURE 103
#define USER_LIST 201
#define USER_LIST_READ_OK 202
#define USER_GROUP 301
#define USER_HEADER 401
#define USER_ARTICLE 501
#define USER_ART_READ_OK 502
#define USER_QUIT_SUCCESS 601
#define USER_COMMAND_SUCCESS 1001
#define USER_COMMAND_FAILURE 1002
/* menu bar postions (order must match items in NEWS.RC) */
#define MENU_EXIT 0
#define MENU_CONNECT 1
#define MENU_GROUP 2
#define MENU_HEADER 3
#define MENU_ARTICLE 4
#define MENU_QUIT 5
#define MENU_BREAK 6
#define MENU_ABOUT 7
/* private */
static int ConnectedFlag = 0; /* TRUE when connected */
static USE_INS hInstance; /* instance variable */
static int WinWidth = 8 * NCOLS; /* width in pixels */
static int WinHeight = 15 * NROWS; /* height in pixels */
static int EchoFlag = 1; /* echo commands if TRUE */
static char Temp[MAX_BUF+8]; /* temporary buffer */
static int InBufLen = 0; /* length of string in InBuffer[] */
static int InBufCmd = 0; /* command */
static char InBuffer[MAX_BUF+1]; /* input buffer */
static SOCKET TheSocket = (SOCKET)-1; /* the socket */
static HCURSOR ArrowCursor; /* arrow cursor */
static HCURSOR WaitCursor; /* hour glass cursor */
/* enable menu bar item */
void EnableMenuBarItems(int nPos1, int nPos2)
{int i;
HMENU hMenu;
hMenu = GetMenu(hMainWnd);
for(i=nPos1;i<=nPos2;i++)
EnableMenuItem(hMenu,i,MF_BYPOSITION | MF_ENABLED);
DrawMenuBar(hMainWnd);
}
/* disable menu bar item */
void DisableMenuBarItems(int nPos1, int nPos2)
{int i;
HMENU hMenu;
hMenu = GetMenu(hMainWnd);
for(i=nPos1;i<=nPos2;i++)
EnableMenuItem(hMenu,i,MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
DrawMenuBar(hMainWnd);
}
/* menu state when not connected, awaiting user input */
void NotConnectedMenuState(void)
{EnableMenuBarItems(MENU_CONNECT, MENU_CONNECT);
DisableMenuBarItems(MENU_GROUP, MENU_BREAK);
}
/* menu state when connected, awaiting user input */
void ConnectedMenuState(void)
{DisableMenuBarItems(MENU_CONNECT, MENU_CONNECT);
EnableMenuBarItems(MENU_GROUP, MENU_BREAK);
}
/* menu state while executing NNTP command */
void DoingCmdMenuState(void)
{DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
EnableMenuBarItems(MENU_BREAK, MENU_BREAK);
}
/* add character to input buffer */
static void Add2Buffer(char Chr)
{int i;
/* add char to input buffer */
switch(Chr)
{case BS:
if(InBufLen>0)
{/* backup on screen */
DisplayChar(BS);
/* remove last char from buffer */
InBufLen--;
}
break;
case ESC:
for(i=1;i<=InBufLen;i++) DisplayChar(BS);
InBufLen = 0;
DestroyCaret();
break;
default:
/* display char */
DisplayChar(Chr);
/* put into buffer */
if(InBufLen<MAX_BUF) InBuffer[InBufLen++] = Chr;
break;
}
}
/* place the cursor in the display window */
static void SetTheFocus(void)
{/* create client area caret */
CreateCaret(hMainWnd,NULL,3,10);
SetCaretPos(PaintGetColPos(),PaintGetRowPos());
ShowCaret(hMainWnd);
}
/* display error message */
static void DisplayError(int Code, LPSTR Msg)
{DisplayString("ERROR: ");
if(Msg) DisplayString(Msg);
if(Code)
{wilErrorText(Code,(LPSTR)Temp,50);
DisplayLine((LPSTR)Temp);
}
}
/* WinMain */
#ifdef WIN32
int WINAPI
#else
int PASCAL
#endif
WinMain(USE_INS hInst, USE_INS hPrevInstance,
USE_PTR szCmdLine, int nCmdShow)
{WNDCLASS wc;
MSG msg;
BOOL Result;
if(!hPrevInstance)
{/* register main window class */
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, "HostIcon");
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "HostMenu";
wc.lpszClassName = "HostWClass";
Result = RegisterClass(&wc);
if(!Result) return FALSE;
}
/* create main window */
hInstance = hInst;
hMainWnd = CreateWindow(
"HostWClass", "News", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
WinWidth, WinHeight,
NULL, NULL,
hInstance, NULL);
ShowWindow(hMainWnd, nCmdShow);
UpdateWindow(hMainWnd);
/* window control loop */
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
} /* end WinMain */
#ifdef WIN32
LRESULT CALLBACK
#else
long FAR PASCAL
#endif
MainWndProc(HWND hWindow,UINT iMsg,WPARAM wParam,LPARAM lParam)
{int Code;
HDC hDC;
PAINTSTRUCT ps;
static LPSTR BufferPtr;
static int Handle = 0;
static char FileName[32];
ULONG Article;
#ifdef WIN32
#else
static FARPROC lpfnAboutDlgProc;
#endif
hMainWnd = hWindow;
switch (iMsg)
{case WM_CREATE:
/* create cursors */
ArrowCursor = LoadCursor(NULL, IDC_ARROW);
WaitCursor = LoadCursor(NULL, IDC_WAIT);
SetCursor(ArrowCursor);
#ifdef WIN32
#else
/* create thunk for Win16 */
lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc,hInstance);
#endif
/* initialize paint module */
PaintInit();
/* attach WINSOCK */
DisplayString("Attaching WINSOCK...");
Code = wilAttach();
DisplayLine("OK");
if(Code<0) DisplayError(Code,"wilAttach fails:");
else
{wsprintf((LPSTR)Temp," Description: %s", wilGetDescription() );
DisplayLine((LPSTR)Temp);
wsprintf((LPSTR)Temp," My HostName: %s", wilGetMyHostName() );
DisplayLine((LPSTR)Temp);
wsprintf((LPSTR)Temp," My HostAddr: %s", wilGetMyHostDotted(0) );
DisplayLine((LPSTR)Temp);
}
/* initialize menus */
NotConnectedMenuState();
break;
case WM_COMMAND:
switch(wParam)
{
case MSG_ABOUT :
#ifdef WIN32
DialogBox(hInstance, "AboutBox", hMainWnd, AboutDlgProc);
#else
DialogBox(hInstance, "AboutBox", hMainWnd, lpfnAboutDlgProc);
#endif
return 0;
case MSG_DEBUG:
SetCursor(WaitCursor);
break;
case MSG_ECHO:
EchoFlag = 1 - EchoFlag;
DisplayString("Echo flag is now ");
if(EchoFlag) DisplayLine("ON");
else DisplayLine("OFF");
break;
case MSG_BREAK:
if(ConnectedFlag) ConnectedMenuState();
else NotConnectedMenuState();
/* cancel any async events */
wilAwaitCancel(TheSocket, hMainWnd);
/* cancel any blocking */
wilCancelBlocking();
break;
case MSG_EXIT:
wilRelease();
DestroyWindow(hMainWnd);
break;
case MSG_NEWS_CONNECT:
InBufCmd = USER_CONNECT;
DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
DisplayString("Enter NNTP server name:");
InBufLen = 0;
SetTheFocus();
break;
case MSG_NEWS_LIST:
InBufCmd = USER_LIST;
DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
POST_MSG(USER_LIST);
break;
case MSG_NEWS_GROUP:
InBufCmd = USER_GROUP;
DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
DisplayString("Enter news group:");
InBufLen = 0;
SetTheFocus();
break;
case MSG_NEWS_HEADER_BYNUMBER:
InBufCmd = USER_HEADER;
DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
DisplayString("Enter (article) header number:");
InBufLen = 0;
SetTheFocus();
break;
case MSG_NEWS_HEADER_CURRENT:
/* send HEAD command, expect multiple text lines back */
AsyncCommand("HEAD", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_MULTIPLE_LINES);
break;
case MSG_NEWS_HEADER_NEXT:
case MSG_NEWS_ARTICLE_NEXT:
/* send NEXT command, expect single text line back */
AsyncCommand("NEXT", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
case MSG_NEWS_HEADER_LAST:
case MSG_NEWS_ARTICLE_LAST:
/* send LAST command, expect single text line back */
AsyncCommand("LAST", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
case MSG_NEWS_ARTICLE_BYNUMBER:
InBufCmd = USER_ARTICLE;
DisableMenuBarItems(MENU_CONNECT, MENU_QUIT);
DisplayString("Enter article number:");
InBufLen = 0;
SetTheFocus();
break;
case MSG_NEWS_ARTICLE_CURRENT:
/* send ARTICLE command, expect multiple text lines back */
AsyncCommand("ARTICLE", USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_MULTIPLE_LINES);
break;
case MSG_NEWS_QUIT:
/* send QUIT to news server */
AsyncCommand("QUIT", USER_QUIT_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
}
break;
case WM_USER: /* posted by WIL */
AsyncProcessMsg(lParam);
break;
case WM_USER+1:
switch(wParam)
{
case USER_CONNECT:
if(lstrlen((LPSTR)InBuffer)==0)
{DisplayError(0,"Missing server name");
break;
}
/* waiting for connection */
DoingCmdMenuState();
SetCursor(WaitCursor);
TheSocket = AsyncConnect(hMainWnd,"NNTP",(LPSTR)InBuffer,
NNTP_PORT, USER_CONN_SUCCESS,
USER_CONN_FAILURE, ASYNC_SINGLE_LINE);
break;
case USER_CONN_SUCCESS:
DisplayLine("CONNECT successful");
ConnectedMenuState();
SetCursor(ArrowCursor);
break;
case USER_CONN_FAILURE:
DisplayLine("CONNECT fails");
NotConnectedMenuState();
SetCursor(ArrowCursor);
break;
/* list groups */
case USER_LIST:
SetCursor(WaitCursor);
/* open file for list */
Handle = _lcreat((LPSTR)"NEWS.LST",0);
if(Handle<0)
{DisplayLine("Cannot create NEWS.LST");
Handle = 0;
POST_MSG(USER_COMMAND_FAILURE);
break;
}
DisplayLine("Saving list to NEWS.LST");
/* send LIST command, expect multiple text lines back */
AsyncCommand("LIST", USER_LIST_READ_OK, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
case USER_LIST_READ_OK:
/* read was successfull */
BufferPtr = AsyncGetBufPtr();
/* check if this is the last line */
if((*BufferPtr=='.')&&(*(BufferPtr+1)=='\r') )
{/* end of list */
DisplayLine("[END]");
POST_MSG(USER_COMMAND_SUCCESS);
break;
}
/* write to disk */
_lwrite(Handle, (LPSTR)BufferPtr, lstrlen((LPSTR)BufferPtr) );
/* read next line */
AsyncRead(USER_LIST_READ_OK, USER_COMMAND_FAILURE, ASYNC_SINGLE_LINE);
break;
/* set group */
case USER_GROUP:
wsprintf((LPSTR)Temp,"GROUP %s", (LPSTR)InBuffer);
/* send GROUP command, expect single text line back */
AsyncCommand((LPSTR)Temp, USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
/* get header by number */
case USER_HEADER:
Article = wilParseDecimal((LPSTR)InBuffer);
wsprintf((LPSTR)Temp,"HEAD %lu", Article);
/* send HEAD command, expect multiple text lines back */
AsyncCommand((LPSTR)Temp, USER_COMMAND_SUCCESS, USER_COMMAND_FAILURE,
ASYNC_MULTIPLE_LINES);
break;
/* get article by number & save to disk */
case USER_ARTICLE:
/* get article number */
Article = wilParseDecimal((LPSTR)InBuffer);
/* construct filename for article */
wsprintf((LPSTR)FileName,"%1lu.ART", Article);
wsprintf((LPSTR)Temp,"Saving article %lu to file '%s'",
Article,(LPSTR)FileName);
DisplayLine((LPSTR)Temp);
/* open file for this article */
Handle = _lcreat((LPSTR)FileName,0);
if(Handle<0)
{DisplayString("Cannot create ");
DisplayLine((LPSTR)FileName);
Handle = 0;
POST_MSG(USER_COMMAND_FAILURE);
break;
}
/* send ARTICLE command, expect 1st line back */
wsprintf((LPSTR)Temp,"ARTICLE %1lu", Article);
AsyncCommand((LPSTR)Temp, USER_ART_READ_OK, USER_COMMAND_FAILURE,
ASYNC_SINGLE_LINE);
break;
case USER_ART_READ_OK:
/* read was successfull */
BufferPtr = AsyncGetBufPtr();
/* check if this is the last line */
if((*BufferPtr=='.')&&(*(BufferPtr+1)=='\r') )
{/* end of this article */
DisplayLine("[END]");
POST_MSG(USER_COMMAND_SUCCESS);
break;
}
/* write line to disk */
_lwrite(Handle, (LPSTR)BufferPtr, lstrlen((LPSTR)BufferPtr) );
/* read next line */
AsyncRead(USER_ART_READ_OK, USER_COMMAND_FAILURE, ASYNC_SINGLE_LINE);
break;
/* command was successfull */
case USER_COMMAND_SUCCESS:
if(Handle)
{_lclose(Handle);
Handle = 0;
}
AsyncSetEcho(EchoFlag);
ConnectedMenuState();
SetCursor(ArrowCursor);
break;
/* command failed */
case USER_COMMAND_FAILURE:
AsyncSetEcho(EchoFlag);
ConnectedMenuState();
SetCursor(ArrowCursor);
break;
/* QUIT command successfull */
case USER_QUIT_SUCCESS:
NotConnectedMenuState();
ConnectedFlag = FALSE;
break;
}
break;
case WM_PAINT:
HideCaret(hMainWnd);
hDC = BeginPaint(hMainWnd, &ps);
SetMapMode(hDC,MM_ANISOTROPIC);
SelectObject(hDC, GetStockObject(OEM_FIXED_FONT) );
PaintMain(hDC,&ps);
EndPaint(hMainWnd,&ps);
SetCaretPos(PaintGetColPos(),PaintGetRowPos());
ShowCaret(hMainWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CHAR:
if(wParam==CR)
{/* user has completed input */
DestroyCaret();
DisplayChar(LF);
InBuffer[InBufLen] = '\0';
/* excute command associated with input buffer */
POST_MSG(InBufCmd);
}
else
{/* add char to input buffer */
Add2Buffer((char) wParam);
}
break;
default:
return (DefWindowProc(hMainWnd, iMsg, wParam, lParam));
}
return 0;
} /* end MainWndProc */